/* -*- mode: C; c-basic-offset: 3; -*- */

/*
   This file is part of Valgrind, a dynamic binary instrumentation
   framework.

   Copyright (C) 2025  Florian Krohm

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 3 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, see <http://www.gnu.org/licenses/>.

   The GNU General Public License is contained in the file COPYING.
*/

#define OPNAME(op) #op, Iop_##op

#define A(x) ARCH_##x

#define ARCH_ppc32    0x0001
#define ARCH_ppc64be  0x0002
#define ARCH_ppc64le  0x0004
#define ARCH_ppc64    (ARCH_ppc64be | ARCH_ppc64le)
#define ARCH_ppc      (ARCH_ppc32 | ARCH_ppc64)
#define ARCH_amd64    0x0008
#define ARCH_x86      0x0010
#define ARCH_s390     0x0020
#define ARCH_mips32   0x0040
#define ARCH_mips64   0x0080
#define ARCH_mipsx    (ARCH_mips32 | ARCH_mips64)    // ARCH_mips does not work
#define ARCH_ALL      0x00FF    // OR of all above

/* FIXME: Add support for nanomips, arm, and riscv.
   When doing so ARCH_ALL needs to be adjusted */
#if 0
#define ARCH_nanomips 0x0100
#define ARCH_arm      0x0200
#define ARCH_arm64    0x0400
#define ARCH_riscv64  0x0800
#endif

#define ONLY(x)        .enabled_arch = A(x)
#define ONLY2(x1,x2)   .enabled_arch = A(x1) | A(x2)
#define EXCEPT(x)      .enabled_arch = ARCH_ALL & ~A(x)
#define EXCEPT2(x1,x2) .enabled_arch = ARCH_ALL & ~(A(x1) | A(x2))
#define EXCEPT3(x1,x2,x3) .enabled_arch = ARCH_ALL & ~(A(x1) | A(x2) | A(x3))

/* Definition of IROps:
   - no IROps having floating point operands or result
   - no IROPs having vector operands or results (V128, V256)
   - no IROPs having integer operands or results with more than 64 bit
*/
   // UNARY
   { OPNAME(Not1),   Ity_I1,  1, Ity_I1,  },
   { OPNAME(Not8),   Ity_I8,  1, Ity_I8,  },
   { OPNAME(Not16),  Ity_I16, 1, Ity_I16, },
   { OPNAME(Not32),  Ity_I32, 1, Ity_I32, },
   { OPNAME(Not64),  Ity_I64, 1, Ity_I64, },

   { OPNAME(1Uto8),  Ity_I8,  1, Ity_I1,  },
// { OPNAME(1Uto16), Ity_I16, 1, Ity_I1,  }, // missing in libvex_ir.h
   { OPNAME(1Uto32), Ity_I32, 1, Ity_I1,  },
   { OPNAME(1Uto64), Ity_I64, 1, Ity_I1,  EXCEPT3(ppc32,x86,mips32) },

   { OPNAME(1Sto8),  Ity_I8,  1, Ity_I1,  },
   { OPNAME(1Sto16), Ity_I16, 1, Ity_I1,  },
   { OPNAME(1Sto32), Ity_I32, 1, Ity_I1,  },
   { OPNAME(1Sto64), Ity_I64, 1, Ity_I1,  },

   { OPNAME(8Uto16), Ity_I16, 1, Ity_I8,  },
   { OPNAME(8Uto32), Ity_I32, 1, Ity_I8,  },
   { OPNAME(8Uto64), Ity_I64, 1, Ity_I8,  EXCEPT2(ppc32, x86) },

   { OPNAME(8Sto16), Ity_I16, 1, Ity_I8,  },
   { OPNAME(8Sto32), Ity_I32, 1, Ity_I8,  },
   { OPNAME(8Sto64), Ity_I64, 1, Ity_I8,  EXCEPT2(ppc32, x86) },

   { OPNAME(16Uto32), Ity_I32, 1, Ity_I16, },
   { OPNAME(16Uto64), Ity_I64, 1, Ity_I16, EXCEPT(ppc32) },
   { OPNAME(16Sto32), Ity_I32, 1, Ity_I16, },
   { OPNAME(16Sto64), Ity_I64, 1, Ity_I16, EXCEPT2(ppc32, x86) },

   { OPNAME(32Uto64), Ity_I64, 1, Ity_I32, },
   { OPNAME(32Sto64), Ity_I64, 1, Ity_I32, },

// { OPNAME(8to1),    Ity_I1, 1, Ity_I8,  }, // missing in libvex_ir.h

// { OPNAME(16to1),   Ity_I1, 1, Ity_I16, }, // missing in libvex_ir.h
   { OPNAME(16to8),   Ity_I8, 1, Ity_I16, },
   { OPNAME(16HIto8), Ity_I8, 1, Ity_I16, },

   { OPNAME(32to1),    Ity_I1,  1, Ity_I32, },
   { OPNAME(32to8),    Ity_I8,  1, Ity_I32, },
   { OPNAME(32to16),   Ity_I16, 1, Ity_I32, },
   { OPNAME(32HIto16), Ity_I16, 1, Ity_I32, },

   { OPNAME(64to1),    Ity_I1,  1, Ity_I64, EXCEPT2(ppc32, x86) },
   { OPNAME(64to8),    Ity_I8,  1, Ity_I64, EXCEPT2(ppc32, x86) },
   { OPNAME(64to16),   Ity_I16, 1, Ity_I64, EXCEPT3(ppc32, x86, mips32) },
   { OPNAME(64to32),   Ity_I32, 1, Ity_I64, },
   { OPNAME(64HIto32), Ity_I32, 1, Ity_I64, },

// { OPNAME(128to64),   Ity_I64, 1, Ity_I128, },      // 128 bit
// { OPNAME(128HIto64), Ity_I64, 1, Ity_I128, },      // 128 bit

   { OPNAME(CmpNEZ8),   Ity_I1,  1, Ity_I8,  },
   { OPNAME(CmpNEZ16),  Ity_I1,  1, Ity_I16, EXCEPT(ppc) },
   { OPNAME(CmpNEZ32),  Ity_I1,  1, Ity_I32, },
   { OPNAME(CmpNEZ64),  Ity_I1,  1, Ity_I64, },

   { OPNAME(CmpwNEZ32), Ity_I32,  1, Ity_I32 },
   { OPNAME(CmpwNEZ64), Ity_I64,  1, Ity_I64 },

   { OPNAME(Left8),  Ity_I8,   1, Ity_I8  },
   { OPNAME(Left16), Ity_I16,  1, Ity_I16 },
   { OPNAME(Left32), Ity_I32,  1, Ity_I32 },
   { OPNAME(Left64), Ity_I64,  1, Ity_I64 },

   { OPNAME(ClzNat32), Ity_I32, 1, Ity_I32, EXCEPT2(amd64, s390) },
   { OPNAME(ClzNat64), Ity_I64, 1, Ity_I64, EXCEPT3(ppc32, x86, mips32) },

   { OPNAME(CtzNat32), Ity_I32, 1, Ity_I32, ONLY2(ppc, x86) },
   { OPNAME(CtzNat64), Ity_I64, 1, Ity_I64, ONLY2(ppc64, amd64) },

   { OPNAME(PopCount32), Ity_I32, 1, Ity_I32, ONLY(ppc)   },
   { OPNAME(PopCount64), Ity_I64, 1, Ity_I64, ONLY(ppc64) },

   // BINARY
   { OPNAME(Add8),    Ity_I8,  2, Ity_I8,  Ity_I8  },
   { OPNAME(Add16),   Ity_I16, 2, Ity_I16, Ity_I16 },
   { OPNAME(Add32),   Ity_I32, 2, Ity_I32, Ity_I32 },
   { OPNAME(Add64),   Ity_I64, 2, Ity_I64, Ity_I64 },

   { OPNAME(Sub8),    Ity_I8,  2, Ity_I8,  Ity_I8  },
   { OPNAME(Sub16),   Ity_I16, 2, Ity_I16, Ity_I16 },
   { OPNAME(Sub32),   Ity_I32, 2, Ity_I32, Ity_I32 },
   { OPNAME(Sub64),   Ity_I64, 2, Ity_I64, Ity_I64, EXCEPT(ppc32) },

   { OPNAME(Mul8),    Ity_I8,  2, Ity_I8,  Ity_I8,  ONLY(s390) },
   { OPNAME(Mul16),   Ity_I16, 2, Ity_I16, Ity_I16, EXCEPT2(ppc, mipsx) },
   { OPNAME(Mul32),   Ity_I32, 2, Ity_I32, Ity_I32, },
   { OPNAME(Mul64),   Ity_I64, 2, Ity_I64, Ity_I64, EXCEPT2(ppc32, x86) },

   { OPNAME(MullU8),  Ity_I16,  2, Ity_I8,  Ity_I8,  EXCEPT(ppc) },
   { OPNAME(MullU16), Ity_I32,  2, Ity_I16, Ity_I16, EXCEPT(ppc) },
   { OPNAME(MullU32), Ity_I64,  2, Ity_I32, Ity_I32, },
// { OPNAME(MullU64), Ity_I128, 2, Ity_I64, Ity_I64, }, // 128 bit

   { OPNAME(MullS8),  Ity_I16,  2, Ity_I8,  Ity_I8,  EXCEPT(ppc) },
   { OPNAME(MullS16), Ity_I32,  2, Ity_I16, Ity_I16, EXCEPT(ppc) },
   { OPNAME(MullS32), Ity_I64,  2, Ity_I32, Ity_I32, },
// { OPNAME(MullS64), Ity_I128, 2, Ity_I64, Ity_I64, }, // 128 bit

   { OPNAME(DivU32),  Ity_I32,  2, Ity_I32,  Ity_I32, ONLY2(ppc, mipsx)   },
   { OPNAME(DivU64),  Ity_I64,  2, Ity_I64,  Ity_I64, ONLY2(ppc64, mips64) },
// { OPNAME(DivU128), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit

   { OPNAME(DivS32),  Ity_I32,  2, Ity_I32,  Ity_I32, ONLY2(ppc, mipsx)   },
   { OPNAME(DivS64),  Ity_I64,  2, Ity_I64,  Ity_I64, ONLY2(ppc64, mips64) },
// { OPNAME(DivS128), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit

   { OPNAME(DivU32E),  Ity_I32,  2, Ity_I32,  Ity_I32, ONLY(ppc) },
// { OPNAME(DivU64E),  Ity_I64,  2, Ity_I64,  Ity_I64, }, // 128 bit
// { OPNAME(DivU128E), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit

   { OPNAME(DivS32E),  Ity_I32,  2, Ity_I32,  Ity_I32, ONLY(ppc) },
// { OPNAME(DivS64E),  Ity_I32,  2, Ity_I32,  Ity_I32, }, // 128 bit
// { OPNAME(DivS128E), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit

   { OPNAME(DivModU32to32),  Ity_I64,  2, Ity_I32, Ity_I32, ONLY(mipsx) },
   { OPNAME(DivModU64to32),  Ity_I64,  2, Ity_I64, Ity_I32, EXCEPT2(ppc, mipsx) },
// { OPNAME(DivModU64to64),  Ity_I64,  2, Ity_I64, Ity_I128 }, // 128 bit
// { OPNAME(DivModU128to64), Ity_I128, 2, Ity_I64, Ity_I128 }, // 128 bit

   { OPNAME(DivModS32to32),  Ity_I64,  2, Ity_I32, Ity_I32, ONLY(mipsx) },
   { OPNAME(DivModS64to32),  Ity_I64,  2, Ity_I64, Ity_I32, EXCEPT2(ppc, mipsx) },
// { OPNAME(DivModS64to64),  Ity_I64,  2, Ity_I64, Ity_I128 }, // 128 bit
// { OPNAME(DivModU128to64), Ity_I128, 2, Ity_I64, Ity_I128 }, // 128 bit

// { OPNAME(ModU128), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit
// { OPNAME(ModS128), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit

   { OPNAME(Shl8),  Ity_I8,  2, Ity_I8,  Ity_I8, EXCEPT(mipsx) },
   { OPNAME(Shl16), Ity_I16, 2, Ity_I16, Ity_I8, EXCEPT(mipsx) },
   { OPNAME(Shl32), Ity_I32, 2, Ity_I32, Ity_I8 },
   { OPNAME(Shl64), Ity_I64, 2, Ity_I64, Ity_I8, EXCEPT(ppc32) },

   { OPNAME(Shr8),  Ity_I8,  2, Ity_I8,  Ity_I8, EXCEPT(mipsx) },
   { OPNAME(Shr16), Ity_I16, 2, Ity_I16, Ity_I8 },
   { OPNAME(Shr32), Ity_I32, 2, Ity_I32, Ity_I8 },
   { OPNAME(Shr64), Ity_I64, 2, Ity_I64, Ity_I8, EXCEPT(ppc32) },

   { OPNAME(Sar8),  Ity_I8,  2, Ity_I8,  Ity_I8, EXCEPT(mipsx) },
   { OPNAME(Sar16), Ity_I16, 2, Ity_I16, Ity_I8 },
   { OPNAME(Sar32), Ity_I32, 2, Ity_I32, Ity_I8 },
   { OPNAME(Sar64), Ity_I64, 2, Ity_I64, Ity_I8, EXCEPT(ppc32) },

   { OPNAME(Or1),   Ity_I1,  2, Ity_I1,  Ity_I1  },
   { OPNAME(Or8),   Ity_I8,  2, Ity_I8,  Ity_I8  },
   { OPNAME(Or16),  Ity_I16, 2, Ity_I16, Ity_I16 },
   { OPNAME(Or32),  Ity_I32, 2, Ity_I32, Ity_I32 },
   { OPNAME(Or64),  Ity_I64, 2, Ity_I64, Ity_I64 },

   { OPNAME(And1),  Ity_I1,  2, Ity_I1,  Ity_I1  },
   { OPNAME(And8),  Ity_I8,  2, Ity_I8,  Ity_I8  },
   { OPNAME(And16), Ity_I16, 2, Ity_I16, Ity_I16 },
   { OPNAME(And32), Ity_I32, 2, Ity_I32, Ity_I32 },
   { OPNAME(And64), Ity_I64, 2, Ity_I64, Ity_I64 },

// { OPNAME(Xor1),  Ity_I1,  2, Ity_I1,  Ity_I1  }, // missing in libvex_ir.h
   { OPNAME(Xor8),  Ity_I8,  2, Ity_I8,  Ity_I8  },
   { OPNAME(Xor16), Ity_I16, 2, Ity_I16, Ity_I16 },
   { OPNAME(Xor32), Ity_I32, 2, Ity_I32, Ity_I32 },
   { OPNAME(Xor64), Ity_I64, 2, Ity_I64, Ity_I64 },

   { OPNAME(CmpEQ8),  Ity_I1,  2, Ity_I8,  Ity_I8,  EXCEPT(ppc) },
   { OPNAME(CmpEQ16), Ity_I1,  2, Ity_I16, Ity_I16, EXCEPT(ppc) },
   { OPNAME(CmpEQ32), Ity_I1,  2, Ity_I32, Ity_I32, },
   { OPNAME(CmpEQ64), Ity_I1,  2, Ity_I64, Ity_I64, EXCEPT(ppc32) },

   { OPNAME(CmpNE8),  Ity_I1,  2, Ity_I8,  Ity_I8,  EXCEPT2(ppc, mipsx) },
   { OPNAME(CmpNE16), Ity_I1,  2, Ity_I16, Ity_I16, EXCEPT2(ppc, mipsx) },
   { OPNAME(CmpNE32), Ity_I1,  2, Ity_I32, Ity_I32, },
   { OPNAME(CmpNE64), Ity_I1,  2, Ity_I64, Ity_I64, EXCEPT2(ppc32, mips32) },

   { OPNAME(CmpLT32U), Ity_I1,  2, Ity_I32, Ity_I32, },
   { OPNAME(CmpLT64U), Ity_I1,  2, Ity_I64, Ity_I64, EXCEPT3(ppc32, x86, mips32) },

   { OPNAME(CmpLT32S), Ity_I1,  2, Ity_I32, Ity_I32, },
   { OPNAME(CmpLT64S), Ity_I1,  2, Ity_I64, Ity_I64, EXCEPT3(ppc32, x86, mips32) },

   { OPNAME(CmpLE32U), Ity_I1,  2, Ity_I32, Ity_I32, },
   { OPNAME(CmpLE64U), Ity_I1,  2, Ity_I64, Ity_I64, EXCEPT3(ppc32, x86, mipsx) },

   { OPNAME(CmpLE32S), Ity_I1,  2, Ity_I32, Ity_I32, },
   { OPNAME(CmpLE64S), Ity_I1,  2, Ity_I64, Ity_I64, EXCEPT3(ppc32, x86, mips32) },

   { OPNAME(CasCmpEQ8),  Ity_I1,  2, Ity_I8,  Ity_I8,  EXCEPT2(ppc, mipsx) },
   { OPNAME(CasCmpEQ16), Ity_I1,  2, Ity_I16, Ity_I16, EXCEPT2(ppc, mipsx) },
   { OPNAME(CasCmpEQ32), Ity_I1,  2, Ity_I32, Ity_I32, EXCEPT(ppc) },
   { OPNAME(CasCmpEQ64), Ity_I1,  2, Ity_I64, Ity_I64, EXCEPT2(ppc, x86) },

   { OPNAME(CasCmpNE8),  Ity_I1,  2, Ity_I8,  Ity_I8,  EXCEPT2(ppc, mipsx) },
   { OPNAME(CasCmpNE16), Ity_I1,  2, Ity_I16, Ity_I16, EXCEPT2(ppc, mipsx) },
   { OPNAME(CasCmpNE32), Ity_I1,  2, Ity_I32, Ity_I32, EXCEPT2(ppc, mipsx) },
   { OPNAME(CasCmpNE64), Ity_I1,  2, Ity_I64, Ity_I64, ONLY2(s390, amd64) },

   { OPNAME(ExpCmpNE8),  Ity_I1,  2, Ity_I8,  Ity_I8,  ONLY(s390) },
   { OPNAME(ExpCmpNE16), Ity_I1,  2, Ity_I16, Ity_I16, ONLY2(s390, x86) },
   { OPNAME(ExpCmpNE32), Ity_I1,  2, Ity_I32, Ity_I32, EXCEPT2(ppc, mipsx) },
   { OPNAME(ExpCmpNE64), Ity_I1,  2, Ity_I64, Ity_I64, ONLY2(s390, amd64) },

   { OPNAME(CmpORD32U), Ity_I32,  2, Ity_I32, Ity_I32, ONLY(ppc) },
   { OPNAME(CmpORD32S), Ity_I32,  2, Ity_I32, Ity_I32, ONLY(ppc) },
   { OPNAME(CmpORD64U), Ity_I64,  2, Ity_I64, Ity_I64, ONLY(ppc64) },
   { OPNAME(CmpORD64S), Ity_I64,  2, Ity_I64, Ity_I64, ONLY(ppc64) },

   { OPNAME(Max32U), Ity_I32,  2, Ity_I32, Ity_I32 },

   { OPNAME(8HLto16),   Ity_I16,  2, Ity_I8,  Ity_I8,  EXCEPT(ppc) },
   { OPNAME(16HLto32),  Ity_I32,  2, Ity_I16, Ity_I16, EXCEPT(ppc) },
   { OPNAME(32HLto64),  Ity_I64,  2, Ity_I32, Ity_I32, },
// { OPNAME(64HLto128), Ity_I128, 2, Ity_I64, Ity_I64, }, // 128 bit
